package com.eu.ebpm.engine.cmd.pvm;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.eu.ebpm.engine.entity.args.Param;
import com.eu.ebpm.engine.entity.deploy.Mission;
import com.eu.ebpm.engine.entity.deploy.Transfer;
import com.eu.ebpm.engine.entity.history.HisTask;
import com.eu.ebpm.engine.entity.runtime.ForkVariable;
import com.eu.ebpm.engine.entity.runtime.TaskEntity;
import com.eu.ebpm.engine.exception.ErrorCode;
import com.eu.ebpm.engine.exception.WorkFlowException;
import com.eu.ebpm.engine.express.VariableType;
import com.eu.ebpm.engine.init.EbpmCache;
import com.eu.ebpm.engine.repository.ExecutionRepository;
import com.eu.ebpm.engine.repository.ForkVariableRepository;
import com.eu.ebpm.engine.repository.HisTaskRepository;
import com.eu.ebpm.engine.repository.TaskRepository;

/**
 * @author wxh
 */
@Component
public class ForkAfterIntoCommand {

	@Autowired
	private ForkVariableRepository forkVariableRepository;
	
	@Autowired
	private TaskRepository taskRepository;
	
	@Autowired
	private ExecutionRepository executionRepository;
	
	@Autowired
	private HisTaskRepository hisTaskRepository;

	/**
	 * 流程跳过ForkAfter往下执行条件：
	 *  	1.1、判断【fork】所有节点完毕
	 *   	1.2、判断【子流程】执行完毕以后再继续往下执行
	 * 
	 * @注意：子流程只需要判断父流程对应子流程是否执行完毕即可。无需递归判断孙子辈流程，因为孙子辈流程没有执行完，子流程则没有执行完毕。
	 * 
	 */
	public Mission execute(Mission m, TaskEntity task, Map<String, Object> variables) {

		// 1、设置forkVariables参数
		setForkVariables(task, variables);

		// 2、如果已经全部执行完毕，查找下一执行任务；否则不做处理，等待fork节点全部执行完毕
		long executionId = task.getExecutionId();
		List<Long> taskIds = taskRepository.selectIdsForUpdate(executionId);
		List<Long> subFlowIds = executionRepository.selectByParentIdForUpdate(executionId);
		if (taskIds.size() > 0 || subFlowIds.size() > 0) {
			return null;
		}

		Mission nextMission = null;
		String transferName = null;
		String transferDesc = null;

		// 3、匹配下一步执行节点
		if (m.getTransfers().size() == 1) {
			
			Transfer t = m.getTransfers().get(0);
			nextMission = t.getToMission();
			transferName = t.getName();
			transferDesc = t.getDesc();
			
		} else {
			
			// 3.1 拿到分支所有调节参数
			List<ForkVariable> forkVariables = forkVariableRepository.list(Param.map("executionId", executionId));
			
			// 3.2 设置匹配map信息
			Map<String, Object> vs = new HashMap<String, Object>();
			for (ForkVariable forkVariable : forkVariables) {
				forkVariable.setValue(forkVariable.getType().transform(forkVariable.getValue()));
				vs.put(forkVariable.getName(), forkVariable.getValue());
				vs.put(forkVariable.getMissionName() + "." + forkVariable.getName(), forkVariable.getValue());
			}
			
			// 3.3 匹配操作
			int result = 0;
			for (Transfer t : m.getTransfers()) {
				if (t.getExpressCondition().isMate(vs)) {
					transferName = t.getName();
					transferDesc = t.getDesc();
					nextMission = t.getToMission();
					result++;
				}
			}
			
			if (result != 1) {
				throw new WorkFlowException(ErrorCode.RU_NOTFOUND_NEXTMISSION, String.format(" ==> 匹配个数:%d", result));
			}

			// 3.4 删除对应的wf_ru_forkVariable参数信息
			forkVariableRepository.delete(Param.map("executionId", executionId));
			
		}

		// 4、插入历史任务执行表
		HisTask hisTask = new HisTask(m.getType(), m.getName(), m.getDesc(), transferName, task.getExecutionId(), task.getRootExecutionId(), m.getId(), null, null, new Date(), new Date());
		hisTask.setTransferDesc(transferDesc);
		hisTaskRepository.insert(hisTask);
		 
		// 5、返回下一步执行任务
		return nextMission;
	}

	private void setForkVariables(TaskEntity task, Map<String, Object> variables) {

		Mission taskMission = EbpmCache.getMission(task.getMissionId());

		if (variables != null) {
			for (String key : variables.keySet()) {
				ForkVariable fv = new ForkVariable(task.getId(), task.getExecutionId(), taskMission.getName(), key, variables.get(key), VariableType.typeOf(variables.get(key)));
				forkVariableRepository.insert(fv);
				// forkVariableRepository.insertHis(fv);
			}
		}

	}

}
